#include "UServer.h"
#include "ucompress.h"
#include "udatabase.h"
#include "ubooksdatabase.h"
#include "ubooksinfo.h"
#include <zlib.h>
#include <QFile>
#include <QDir>
#include <QByteArray>
#include <QCoreApplication>
#include <json/json.h>
#include <iostream>

UServer::UServer(QWidget *parent)
    : QObject(parent)
    , udpSocket(new QUdpSocket(this))
{
    readConfig(); //读取配置文件
    connect(udpSocket, &QUdpSocket::readyRead, this, &UServer::onServerReadyRead);
    if (!udpSocket->bind(QHostAddress::Any, port))
        qDebug() << "监听" <<port <<"端口失败";
    else 
        qDebug() << "正在监听端口号:" << port;
}

OPERATOR UServer::getOperatorType(const QByteArray& byteArray) //获取当前字段的操作类型，转为OP return
{
    OPERATOR Type;
    QDataStream ds(byteArray);
    ds >> Type;
    return Type;
}

QByteArray UServer::getData(const QByteArray& byteArray)
{
    QByteArray data;
    OPERATOR Type;
    QDataStream ds(byteArray);
    ds >> Type >> data;
    return data;
}

void UServer::onServerReadyRead()
{
  
    QByteArray datagram;
    datagram.resize(int(udpSocket->pendingDatagramSize()));
    QHostAddress ip;
    quint16 port;
    udpSocket->readDatagram(datagram.data(), datagram.size(), &ip, &port);

    //解析数据，获取操作类型OP 

    qDebug() << static_cast<int>(getOperatorType(datagram));
    switch (getOperatorType(datagram))  //执行相应操作
    {
    case OPERATOR::SAMEINFO:     returnSameInfo(datagram, ip, port); break;
    case OPERATOR::JSONINFO:     returnJsonFile(ip, port); break;
    case OPERATOR::UPDATEINFO:   writeJsonToFile(datagram, ip, port); break;
    case OPERATOR::ADDBOOK:      addBookToDatabase(datagram, ip, port); break;
    case OPERATOR::QUERYBOOK:    queryBookFromDatabase(datagram, ip, port); break;
    case OPERATOR::DELETEBOOK:   deleteBookFromDatabase(datagram, ip, port); break;
    case OPERATOR::REVISEBOOK:   reviseBookFrmoDatabase(datagram, ip, port); break;
    case OPERATOR::UNKNINFO:     qDebug() << "识别失败"; break;
    }
}

UServer::~UServer()
{}

void UServer::returnSameInfo(const QByteArray& datagram, QHostAddress& ip, quint16 port)
{
    udpSocket->writeDatagram(datagram, ip, port);
}

void UServer::returnJsonFile(QHostAddress& ip, quint16& port)
{
    QByteArray data = serialize(OPERATOR::JSONINFO)+ReadJsonToByteArray("newestBookInfo.json");
    udpSocket->writeDatagram(data, ip, port);
}

void UServer::writeJsonToFile(const QByteArray& datagram, QHostAddress& ip, quint16 port)
{
    QString fileName("newestBookInfo.json");
    QFile file(fileName);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QByteArray returnInfoError = serialize(getOperatorType(datagram), QString("Json更新失败"));
        udpSocket->writeDatagram(returnInfoError, ip, port);
    }
    else{
        file.write(getData(datagram));
        file.close();
        bool res = UCompress::CompressJsonFile(fileName);
        QByteArray returnInfo = serialize(getOperatorType(datagram), QString("Json文本已更新"));
        udpSocket->writeDatagram(returnInfo, ip, port);
    }
    file.close();
}

void UServer::addBookToDatabase(const QByteArray& datagram, QHostAddress& ip, quint16 port)
{
    //QByteArray title,author,press,isbn,date,image;
    QString jsonString;
    OPERATOR Type;
    QDataStream ds(datagram);
    ds >> Type >> jsonString;

    Json::CharReaderBuilder reader;
    Json::Value parsedRoot;
    std::string errs;
    std::istringstream s(jsonString.toStdString());

    bool parsingSuccessful = Json::parseFromStream(reader, s, &parsedRoot, &errs);
    if (!parsingSuccessful) {
        std::cerr << "Failed to parse JSON: " << errs << std::endl;
        return;
    }

    bool ret = UBooksDatabase::Instance()->queryBookByIsbn(QString::fromStdString(parsedRoot["isbn"].asString()));
    if (ret == false)
    {
        QString prompt = "添加失败";
        udpSocket->writeDatagram(serialize(OPERATOR::ADDBOOK, prompt.toUtf8()), ip, port);
    }
    else if (ret == true)
    {
        UBooksDatabase::Instance()->addBook(QString::fromStdString(parsedRoot["isbn"].asString()),
                                            QString::fromStdString(parsedRoot["title"].asString()),
                                            QString::fromStdString(parsedRoot["author"].asString()),
                                            QString::fromStdString(parsedRoot["press"].asString()),
                                            QString::fromStdString(parsedRoot["date"].asString()),
                                            QString::fromStdString(parsedRoot["image"].asString()));
        QString prompt = "添加成功";
        udpSocket->writeDatagram(serialize(OPERATOR::ADDBOOK, prompt.toUtf8()), ip, port);
    }
}

void UServer::queryBookFromDatabase(const QByteArray& datagram, QHostAddress& ip, quint16 port)
{
    qDebug() << __func__;
    QString prompt;
    QString jsonString;
    OPERATOR Type;
    QDataStream ds(datagram);
    ds >> Type >> jsonString;

    Json::CharReaderBuilder reader;
    Json::Value parsedRoot;
    std::string errs;
    std::istringstream s(jsonString.toStdString());

    bool parsingSuccessful = Json::parseFromStream(reader, s, &parsedRoot, &errs);
    if (!parsingSuccessful) {
        std::cerr << "解析JSON错误 " << errs << std::endl;
        return;
    }

    QString list = UBooksDatabase::Instance()->queryBook(QString::fromStdString(parsedRoot["title"].asString()),
                        QString::fromStdString(parsedRoot["isbn"].asString()), QString::fromStdString(parsedRoot["author"].asString()));
    if(list.isEmpty() == false)
    {
        prompt = "书籍信息列表不为空";
        udpSocket->writeDatagram(serialize(OPERATOR::QUERYBOOK, list), ip, port);
    }
    else
        prompt = "书籍信息列表为空"; 
    qDebug() << prompt;
}

void UServer::deleteBookFromDatabase(const QByteArray& datagram, QHostAddress& ip, quint16 port)
{
    qDebug() << __func__;
    QString jsonString;
    OPERATOR Type;
    QDataStream ds(datagram);
    ds >> Type >> jsonString;

    Json::CharReaderBuilder reader;
    Json::Value parsedRoot;
    std::string errs;
    std::istringstream s(jsonString.toStdString());

    bool parsingSuccessful = Json::parseFromStream(reader, s, &parsedRoot, &errs);
    if (!parsingSuccessful) {
        std::cerr << "解析JSON错误 " << errs << std::endl;
        return;
    }
    qDebug() << QString::fromStdString(parsedRoot["isbn"].asString());
    UBooksDatabase::Instance()->deleteBook(QString::fromStdString(parsedRoot["isbn"].asString()));   
}

void UServer::reviseBookFrmoDatabase(const QByteArray& datagram, QHostAddress& ip, quint16 port)
{
    qDebug() << __func__;
    QString prompt;
    QString jsonString;
    OPERATOR Type;
    QDataStream ds(datagram);
    ds >> Type >> jsonString;

    Json::CharReaderBuilder reader;
    Json::Value parsedRoot;
    std::string errs;
    std::istringstream s(jsonString.toStdString());

    bool parsingSuccessful = Json::parseFromStream(reader, s, &parsedRoot, &errs);
    if (!parsingSuccessful) {
        std::cerr << "解析JSON错误 " << errs << std::endl;
        return;
    }
    qDebug() << QString::fromStdString(parsedRoot["initisbn"].asString());
    qDebug() << QString::fromStdString(parsedRoot["isbn"].asString());

    if (parsedRoot["initisbn"].asString() == parsedRoot["isbn"].asString())
    {
        UBooksDatabase::Instance()->changeBook(QString::fromStdString(parsedRoot["isbn"].asString()),
            QString::fromStdString(parsedRoot["title"].asString()),
            QString::fromStdString(parsedRoot["author"].asString()),
            QString::fromStdString(parsedRoot["press"].asString()),
            QString::fromStdString(parsedRoot["date"].asString()),
            QString::fromStdString(parsedRoot["initisbn"].asString()));
        prompt = "修改成功";
       
    }
    else if (parsedRoot["initisbn"].asString() != parsedRoot["isbn"].asString())
    {
        //当返回结果为true时，表明修改后的ISBN没有重复
        if (UBooksDatabase::Instance()->queryBookByIsbn(QString::fromStdString(parsedRoot["isbn"].asString())) == false)
            prompt = "输入的ISBN号已经存在，无法修改";
        else
        {
            UBooksDatabase::Instance()->changeBook(QString::fromStdString(parsedRoot["isbn"].asString()),
                QString::fromStdString(parsedRoot["title"].asString()),
                QString::fromStdString(parsedRoot["author"].asString()),
                QString::fromStdString(parsedRoot["press"].asString()),
                QString::fromStdString(parsedRoot["date"].asString()),
                QString::fromStdString(parsedRoot["initisbn"].asString()));
            prompt = "修改成功";
        }

    }
    udpSocket->writeDatagram(serialize(OPERATOR::REVISEBOOK, prompt.toUtf8()), ip, port);
}

QByteArray UServer::ReadJsonToByteArray(const QString& filename) //读取文件内容
{
    QFile file(filename);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        qDebug() << "文件打开失败";
        return 0;
    }
    QByteArray byteArray = file.readAll();
    return byteArray;
}

void UServer::readConfig()
{
    QString iniFilePath = QCoreApplication::applicationDirPath() + "/UServer_config.ini";
    QSettings settings(iniFilePath, QSettings::IniFormat);
    port = settings.value("Network/Port").toInt();
}
